﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace YummyGame.Framework
{
    public class ExpressionParser
    {
        private Stack<Tuple<int, int>> bracketStacks = new Stack<Tuple<int, int>>();
        private Dictionary<Tuple<int, int>, Expression> finishResult = new Dictionary<Tuple<int, int>, Expression>();
        private string expression;
        private ExpressionContext context;

        public ExpressionParser(ExpressionContext context = null)
        {
            this.context = context;
        }

        public Expression Parse(string expression)
        {
            this.expression = expression;
            Prepare();
            PushStack(this.expression, 0, this.expression.Length - 1);

            while (bracketStacks.Count > 0)
            {
                AnalyizeStack();
            }
            foreach (var res in finishResult)
            {
                return res.Value;
            }
            return null;
        }

        private void Prepare()
        {
            this.expression = this.expression.Replace(" ", "");
            this.expression = "(" + this.expression + ")";
            bracketStacks.Clear();
            finishResult.Clear();
        }

        private void AnalyizeStack()
        {
            var range = bracketStacks.Pop();
            var startIndex = range.Item1;
            var endIndex = range.Item2;

            Expression first = null;
            Expression second = null;

            Type operationType = null;
            List<char> charValue = new List<char>();
            for (int i = startIndex; i < endIndex+1; i++)
            {
                if (expression[i] == '(')
                {
                    if (charValue.Count > 0)
                    {
                        throw new Exception("异常");
                    }
                    var finishRange = GetFinishRange(i+1);
                    if (finishRange == null) throw new Exception("解释错误");
                    if(first == null)
                        first = finishResult[finishRange];
                    else
                    {
                        second = finishResult[finishRange];
                    }
                    finishResult.Remove(finishRange);
                    i = finishRange.Item2 + 1;
                }
                else
                {
                    if (expression[i] == '+' || expression[i] == '-' || expression[i] == '*' || expression[i] == '/')
                    {
                        if (operationType != null)
                        {
                            if(second == null)
                            {
                                if (charValue.Count > 0)
                                    first = (ExpressionOperation)Activator.CreateInstance(operationType,
                                        new object[] { first, GetExpression(charValue) });
                                else
                                    throw new Exception("操作符错误");
                            }
                            else
                            {
                                first = (ExpressionOperation)Activator.CreateInstance(operationType,
                                        new object[] { first, second});
                            }
                            second = null;
                            operationType = null;
                        }

                        if(first == null)
                        {
                            first = GetExpression(charValue);
                        }
                        else
                        {
                            if (second != null)
                            {
                                first = (ExpressionOperation)Activator.CreateInstance(operationType,
                                    new object[] { first, second });
                                operationType = null;
                                second = null;
                            }
                        }
                        
                        if (expression[i] == '+')
                        {
                            if (operationType != null) throw new Exception("操作符错误");
                            operationType = typeof(ExpressionAdd);
                        }
                        else if (expression[i] == '-')
                        {
                            if (operationType != null) throw new Exception("操作符错误");
                            operationType = typeof(ExpressionSub);
                        }
                        else if (expression[i] == '*')
                        {
                            if (operationType != null) throw new Exception("操作符错误");
                            operationType = typeof(ExpressionMul);
                        }
                        else if (expression[i] == '/')
                        {
                            if (operationType != null) throw new Exception("操作符错误");
                            operationType = typeof(ExpressionDiv);
                        }
                        charValue.Clear();
                    }
                    
                    else
                    {
                        charValue.Add(expression[i]);
                    }
                }
            }
            if (first == null)
            {
                if (charValue.Count > 0)
                {
                    first = GetExpression(charValue);
                }
                else
                    throw new Exception("空字符串");
            }
            else
            {
                if (operationType != null)
                {
                    if (second == null)
                    {
                        if(charValue.Count == 0) throw new Exception("缺少第二个操作数");
                        first = (ExpressionOperation)Activator.CreateInstance(operationType,
                        new object[] { first, GetExpression(charValue) });
                    }
                    else
                    {
                        first = (ExpressionOperation)Activator.CreateInstance(operationType,
                        new object[] { first, second });
                    }
                    second = null;
                    operationType = null;
                }
            }
            
            charValue.Clear();
            finishResult.Add(range, first);
        }

        private Expression GetExpression(List<char> values)
        {
            if (values[0] >= '0' && values[0] <= '9')
            {
                return new ExpressionConst(values);
            }
            else
            {
                return new ExpressionVariable(context, values);
            }
        }

        private Tuple<int, int> GetFinishRange(int index)
        {
            foreach (var range in finishResult.Keys)
            {
                if (index == range.Item1) return range;
            }
            return null;
        }

        private void PushStack(string expression,int start,int end)
        {
            int brackets = 0;
            int nextStart = 0;
            for (int i = start; i <= end; i++)
            {
                if(expression[i] == '(')
                {
                    if (brackets == 0) nextStart = i + 1;
                    brackets ++;
                }else if(expression[i] == ')')
                {
                    brackets--;
                    if(brackets<0) throw new Exception("表达式错误:" + i);
                    else if(brackets == 0)
                    {
                        if (i == nextStart) throw new Exception("没有输入表达式内容" + i);
                        bracketStacks.Push(new Tuple<int, int>(nextStart, i - 1));
                        PushStack(expression, nextStart, i - 1);
                    }
                }
            }
        }
    }
}
